﻿Function Import-Templates
{
    [cmdletbinding(DefaultParameterSetName="none")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [ValidateScript({Test-Path $_ -PathType Leaf})] 
        [String] 
        $TemplateFile,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [Switch] 
        $PluralizeCollectionTerms

        )

    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Import-Templates from '$TemplateFile'"
    }
    End
    {
        write-verbose "End Import-Templates from '$TemplateFile'"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process 
    {

        #Create the root Object receiver
        $templateContainer = New-Object psobject
        
        #Select root node from template file
        $templateRootNode = Select-Xml -Path $TemplateFile -XPath "/*"
        $templateContainer | Add-Member -MemberType NoteProperty ElementType -Value $templateRootNode.Node.LocalName       

        if ($templateRootNode)
        {
            #Copy attributes from the root node on the templateContainer
            Add-XmlAttributesToObject -Source $templateRootNode.Node -Target $templateContainer

            #Browse child nodes and dynamically create them in hashtbale
            $templateRootNode.Node.SelectNodes("*") | ForEach-Object {
            

                $propertyName = $_.LocalName
                if ($PluralizeCollectionTerms)
                {
                    if (!$propertyName.EndsWith("s"))
                    {
                        $propertyName += "s"
                    }
                }

                $existingPropertyMember = $templateContainer | Get-Member -Name $propertyName
                if (!$existingPropertyMember)
                {
                    $existingProperty = @{}
                    $templateContainer | Add-Member -MemberType NoteProperty -Name $propertyName -Value $existingProperty
                }

                
                #Verifiy that xml element have a unique Key    
                Assert-XmlAttribute -xmlElement $_ -xmlAttribute uniqueKey

                $templateObject = New-DynamicObject_v2 -Source $_
                $templateContainer.$($propertyName).Add($templateObject.UniqueKey, $templateObject)
            }
        }

        $templateContainer

    }
}


<#
.SYNOPSIS
Read a xml template file and load all xml element in the Teamplates hashtable
Return a sumary object to retrieve additional information on the root node and to give the status of the import

.DESCRIPTION
Read a xml template file and load all xml element in the Teamplates hashtable
Return a sumary object to retrieve additional information on the root node and to give the status of the import

.PARAMETER Templates
Required. The hashtable templates container to load the file

.PARAMETER PropertyName
Required. The collection property name to use

.PARAMETER CurrentObject
Required. The current object to add to the collection
#>
Function Import-TemplatesFromXmlFile
{
    [cmdletbinding(DefaultParameterSetName="none")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [System.Collections.Hashtable] 
        $Templates,

        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [ValidateScript({Test-Path $_ -PathType Leaf})] 
        [String] 
        $TemplateFilePath,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [Switch] 
        $PluralizeCollectionTerms,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [Switch] 
        $OverrideExistingTemplate

    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew()
        $eventId = Publish-ToMiddlewareLogs -Log (Get-LogMessage -Command $PSCmdlet.MyInvocation.MyCommand -Message "Start" -AdditionalData $PSBoundParameters)
    }
    End
    {
        $watch.Stop()
        $eventId = Publish-ToMiddlewareLogs -Log (Get-LogMessage -Command $PSCmdlet.MyInvocation.MyCommand -UniqueId $eventId -Message "End" -AdditionalData @{Duration=$watch.Elapsed})
    }
    Process
    {
        $summary = New-Object PSObject -Property @{
                                                   TemplateFilePath=$TemplateFilePath
                                                   PluralizeCollectionTerms=$PluralizeCollectionTerms
                                                   Status=$true
                                                   Errors=@()
                                                   Warnings=@()
                                                   NbTemplates=0
                                                   RejectedTemplates=@()
                                                   TemplateInformation=(New-Object PSObject)
                                                   }

        try
        {
            #Get full Path from TemplateFilePath argument
            $safeTemplateFilePath = Resolve-Path -Path $TemplateFilePath
            $summary.TemplateFilePath = $safeTemplateFilePath.ProviderPath

            $templateRootNode = Select-Xml -Path $summary.TemplateFilePath -XPath "/*"
            $summary.TemplateInformation | Add-Member -MemberType NoteProperty ElementType -Value $templateRootNode.LocalName
            Add-XmlAttributesToObject -Source $templateRootNode.Node -Target $summary.TemplateInformation

            #Browse child nodes in the template file and dynamically create them in hashtbale
            $templateRootNode.Node.SelectNodes("*") | ForEach-Object {

                #Verifiy that xml element have a unique Key    
                Assert-XmlAttribute -xmlElement $_ -xmlAttribute uniqueKey

                $templateObject = New-DynamicObject_v2 -Source $_
                $uniqueKey = Calculate-TemplateUniqueKey -TemplateType $templateObject.ElementType -TemplateKey $templateObject.UniqueKey

                $existingTemplate = Find-Template -Templates $Templates -TemplateType $templateObject.ElementType -TemplateUniqueKey $uniqueKey -IgnoreMissingTemplate
                if (-not $existingTemplate)
                {
                    $Templates.Add($uniqueKey, $templateObject)
                    $summary.NbTemplates += 1
                } 
                else
                {
                    if ($OverrideExistingTemplate)
                    {
                        $Templates.$uniqueKey = $templateObject
                        $summary.Warnings += "Override existing template with key $uniqueKey"
                        $summary.NbTemplates += 1
                    }
                    else
                    {
                        $summary.Errors += "Rejected Template $uniqueKey because an existing template already exists with the samekey"
                        $summary.RejectedTemplates += $templateObject
                    }
                }                
            }
            
        }
        catch [Exception]
        {
            $summary.status = $false
            $summary.Errors += $_
            Publish-ToMiddlewareLogs -Log (Get-LogMessage -Command $PSCmdlet.MyInvocation.MyCommand -UniqueId $eventId -Category Error -Message "Error" -AdditionalData @{Exception=$_}) | Out-Null

        }
        
        $summary

    }
}




Function Get-TemplateProduct_v2
{
    [cmdletbinding(DefaultParameterSetName="none")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [PSObject] 
        $Template,

        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [String] 
        $Version,

        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [Validateset("x86","x64")]
        [String] 
        $Architecture,

        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [Validateset("Package","Archive","MsDeployPackage")]
        [String] 
        $PackageType,


        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [String] 
        $InstallationTemplateName="standard"

        )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew()
        $eventId = Publish-ToMiddlewareLogs -Log (Get-LogMessage -Command $PSCmdlet.MyInvocation.MyCommand -Message "Start" -AdditionalData $PSBoundParameters)
    }
    End
    {
        $watch.Stop()
        $eventId = Publish-ToMiddlewareLogs -Log (Get-LogMessage -Command $PSCmdlet.MyInvocation.MyCommand -UniqueId $eventId -Message "End" -AdditionalData @{Duration=$watch.Elapsed})
    }
    Process
    {
        #Ensure the template type before parsing its parameters
        if ($Template.ElementType -ne 'product') {throw "Template '$($Template.UniqueKey)' has a type of '$($Template.ElementType)' is not a product Template"}

        #Create a new object and populate direct members from the template
        $productTemplate = New-Object PSOBject

        #Find the correct package for version, architecture and package type
        $package =  $Template.Packages | ? {$_.Version -eq $Version -and $_.architecture -eq $Architecture -and $_.packageType -eq $PackageType}
        if (-not $package) {throw "Template '$($Template.UniqueKey)' has no package of type '$PackageType' for architecture '$Architecture' and Version '$Version'"}
        Clone-Member -Source $package -Target $productTemplate -All -Filter {$_.name -notin 'uniqueKey','level','ElementType'}
        $productTemplate | Add-Member -MemberType NoteProperty -Name PackageKey -Value $package.UniqueKey

        #Find the installation templates for this package
        $installationTemplate = $Template.InstallationTemplates | ? {$_.uniquekey -eq $InstallationTemplateName}
        if (-not $installationTemplate) {throw "Template '$($Template.UniqueKey)' has no installer '$InstallationTemplateName'"}
        Clone-Member -Source $installationTemplate -Target $productTemplate -All -Filter {$_.name -notin 'uniqueKey','level','ElementType'}
        $productTemplate | Add-Member -MemberType NoteProperty -Name InstallerKey -Value $installationTemplate.UniqueKey

        Clone-Member -Source $Template -Target $productTemplate -Filter {$_.Name -ne 'Level'}
        $productTemplate
    }

}

Function Find-Template
{
    [cmdletbinding(DefaultParameterSetName="none")]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [System.Collections.Hashtable] 
        $Templates,

        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [Validateset("Middleware","Server","Product","Application")]
        [String] 
        $TemplateType,

        [Parameter(Mandatory=$true,ValueFromPipeline=$false)]
        [String] 
        $TemplateUniqueKey,

        [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
        [Switch] 
        $IgnoreMissingTemplate
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew()
        $eventId = Publish-ToMiddlewareLogs -Log (Get-LogMessage -Command $PSCmdlet.MyInvocation.MyCommand -Message "Start" -AdditionalData $PSBoundParameters)
    }
    End
    {
        $watch.Stop()
        $eventId = Publish-ToMiddlewareLogs -Log (Get-LogMessage -Command $PSCmdlet.MyInvocation.MyCommand -UniqueId $eventId -Message "End" -AdditionalData @{Duration=$watch.Elapsed})
    }
    Process
    {
        #Retrieve the template
        $key = Calculate-TemplateUniqueKey -TemplateType $TemplateType -TemplateKey $TemplateUniqueKey

        if ((-not $Templates.ContainsKey($key)) -and (-not $IgnoreMissingTemplate))
        {
            throw "'$TemplateType' template '$TemplateUniqueKey' doesn't exist in the manifest templates collection"
        }

        #return the template
        $Templates.$key

    }
}

function Calculate-TemplateUniqueKey
{
   Param( 
    [String]$TemplateType,
    [String]$TemplateKey
    )
    Process
    {
        #The key is [TemplateType]_[TemplateUniqueKey]
        "{0}_{1}" -f $TemplateType,$TemplateKey
    }

}

